home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue39 / userint / DockForm.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-08-06  |  6.6 KB  |  207 lines

  1. unit DockForm;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus,
  7.   ExtCtrls, StdCtrls;
  8.  
  9. type
  10.   TDockableForm = class(TForm)
  11.     Memo1: TMemo;
  12.     procedure FormDockOver(Sender: TObject; Source: TDragDockObject; X,
  13.       Y: Integer; State: TDragState; var Accept: Boolean);
  14.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  15.     procedure FormShow(Sender: TObject);
  16.   private
  17.     function ComputeDockingRect(var DockRect: TRect; MousePos: TPoint): TAlign;
  18.     procedure CMDockClient(var Message: TCMDockClient); message CM_DOCKCLIENT;
  19.   public
  20.   end;
  21.  
  22.  
  23. implementation
  24.  
  25. {$R *.DFM}
  26.  
  27. uses ComCtrls, TabHost, ConjoinHost, Editor;
  28.  
  29. function VisibleDockClientCount(Control: TWinControl): Integer;
  30. var
  31.   I: Integer;
  32. begin
  33.   Result := 0;
  34.   for I := 0 to Control.DockClientCount-1 do
  35.     if Control.DockClients[I].Visible then Inc(Result);
  36. end;
  37.  
  38. procedure TDockableForm.FormDockOver(Sender: TObject;
  39.   Source: TDragDockObject; X, Y: Integer; State: TDragState;
  40.   var Accept: Boolean);
  41. var
  42.   ARect: TRect;
  43. begin
  44.   Accept := (Source.Control is TDockableForm);
  45.   //Draw dock preview depending on where the cursor is relative to our client area
  46.   if Accept and (ComputeDockingRect(ARect, Point(X, Y)) <> alNone) then
  47.     Source.DockRect := ARect;
  48. end;
  49.  
  50. function TDockableForm.ComputeDockingRect(var DockRect: TRect; MousePos: TPoint): TAlign;
  51. var
  52.   DockTopRect,
  53.   DockLeftRect,
  54.   DockBottomRect,
  55.   DockRightRect,
  56.   DockCenterRect: TRect;
  57. begin
  58.   Result := alNone;
  59.   //divide form up into docking "Zones"
  60.   DockLeftRect.TopLeft := Point(0, 0);
  61.   DockLeftRect.BottomRight := Point(ClientWidth div 5, ClientHeight);
  62.  
  63.   DockTopRect.TopLeft := Point(ClientWidth div 5, 0);
  64.   DockTopRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight div 5);
  65.  
  66.   DockRightRect.TopLeft := Point(ClientWidth div 5 * 4, 0);
  67.   DockRightRect.BottomRight := Point(ClientWidth, ClientHeight);
  68.  
  69.   DockBottomRect.TopLeft := Point(ClientWidth div 5, ClientHeight div 5 * 4);
  70.   DockBottomRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight);
  71.  
  72.   DockCenterRect.TopLeft := Point(ClientWidth div 5, ClientHeight div 5);
  73.   DockCenterRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight div 5 * 4);
  74.  
  75.   //Find out where the mouse cursor is, to decide where to draw dock preview.
  76.   if PtInRect(DockLeftRect, MousePos) then
  77.     begin
  78.       Result := alLeft;
  79.       DockRect := DockLeftRect;
  80.       DockRect.Right := ClientWidth div 2;
  81.     end
  82.   else
  83.     if PtInRect(DockTopRect, MousePos) then
  84.       begin
  85.         Result := alTop;
  86.         DockRect := DockTopRect;
  87.         DockRect.Left := 0;
  88.         DockRect.Right := ClientWidth;
  89.         DockRect.Bottom := ClientHeight div 2;
  90.       end
  91.     else
  92.       if PtInRect(DockRightRect, MousePos) then
  93.         begin
  94.           Result := alRight;
  95.           DockRect := DockRightRect;
  96.           DockRect.Left := ClientWidth div 2;
  97.         end
  98.       else
  99.         if PtInRect(DockBottomRect, MousePos) then
  100.           begin
  101.             Result := alBottom;
  102.             DockRect := DockBottomRect;
  103.             DockRect.Left := 0;
  104.             DockRect.Right := ClientWidth;
  105.             DockRect.Top := ClientHeight div 2;
  106.          end
  107.         else
  108.           if PtInRect(DockCenterRect, MousePos) then
  109.           begin
  110.             Result := alClient;
  111.             DockRect := DockCenterRect;
  112.           end;
  113.   if Result = alNone then Exit;
  114.  
  115.   //DockRect is in screen coordinates.
  116.   DockRect.TopLeft := ClientToScreen(DockRect.TopLeft);
  117.   DockRect.BottomRight := ClientToScreen(DockRect.BottomRight);
  118. end;
  119.  
  120. procedure TDockableForm.FormClose(Sender: TObject;
  121.   var Action: TCloseAction);
  122. begin
  123.   //the action taken depends on how the form is docked.
  124.  
  125.   if (HostDockSite is TConjoinDockHost) then
  126.   begin
  127.     //remove the form's caption from the conjoin dock host's caption list
  128.     TConjoinDockHost(HostDockSite).UpdateCaption(Self);
  129.  
  130.     //if we're the last visible form on a conjoined form, hide the form
  131.     if VisibleDockClientCount(HostDockSite) <= 1 then
  132.       HostDockSite.Hide;
  133.   end;
  134.  
  135.   //if docked to a panel, tell the panel to hide itself. If there are other
  136.   //visible dock clients on the panel, it ShowDockPanel won't allow it to
  137.   //be hidden
  138.   if (HostDockSite is TPanel) then
  139.     EditWin.ShowDockPanel(HostDockSite as TPanel, False);
  140.  
  141.   Action := caHide;
  142. end;
  143.  
  144. procedure TDockableForm.CMDockClient(var Message: TCMDockClient);
  145. var
  146.   ARect: TRect;
  147.   DockType: TAlign;
  148.   Host: TForm;
  149.   Pt: TPoint;
  150. begin
  151.   //Overriding this message allows the dock form to create host forms
  152.   //depending on the mouse position when docking occurs. If we don't override
  153.   //this message, the form will use VCL's default DockManager.
  154.  
  155.   //NOTE: the only time ManualDock can be safely called during a drag
  156.   //operation is we override processing of CM_DOCKCLIENT.
  157.  
  158.   if Message.DockSource.Control is TDockableForm then
  159.   begin
  160.  
  161.     //Find out how to dock (Using a TAlign as the result of ComputeDockingRect)
  162.     Pt.x := Message.MousePos.x;
  163.     Pt.y := Message.MousePos.y;
  164.     DockType := ComputeDockingRect(ARect, Pt);
  165.  
  166.     //if we are over a dockable form docked to a panel in the
  167.     //main window, manually dock the dragged form to the panel with
  168.     //the correct orientation.
  169.     if (HostDockSite is TPanel) then
  170.     begin
  171.       Message.DockSource.Control.ManualDock(HostDockSite, nil, DockType);
  172.       Exit;
  173.     end;
  174.  
  175.     //alClient => Create a TabDockHost and manually dock both forms to the PageControl
  176.     //owned by the TabDockHost.
  177.     if DockType = alClient then
  178.     begin
  179.       Host := TTabDockHost.Create(Application);
  180.       Host.BoundsRect := Self.BoundsRect;
  181.       Self.ManualDock(TTabDockHost(Host).PageControl1, nil, alClient);
  182.       Message.DockSource.Control.ManualDock(TTabDockHost(Host).PageControl1, nil, alClient);
  183.       Host.Visible := True;
  184.     end
  185.     //if DockType <> alClient, create the ConjoinDockHost and manually dock both
  186.     //forms to it. Be sure to make dockable forms non-dockable when hosted by
  187.     // ConjoinDockForm, since it is using the VCL default DockManager.
  188.     else begin
  189.       Host := TConjoinDockHost.Create(Application);
  190.       Host.BoundsRect := Self.BoundsRect;
  191.       Self.ManualDock(Host, nil, alNone);
  192.       Self.DockSite := False;
  193.       Message.DockSource.Control.ManualDock(Host, nil, DockType);
  194.       TDockableForm(Message.DockSource.Control).DockSite := False;
  195.       Host.Visible := True;
  196.     end;
  197.   end;
  198. end;
  199.  
  200. procedure TDockableForm.FormShow(Sender: TObject);
  201. begin
  202.   if HostDockSite is TConjoinDockHost then
  203.     TConjoinDockHost(HostDockSite).UpdateCaption(nil);
  204. end;
  205.  
  206. end.
  207.